package com.im.tcp.server;

import com.im.codec.MessageDecoder;
import com.im.codec.MessageEncoder;
import com.im.tcp.config.TcpConfig;
import com.im.tcp.feign.FeignMessageService;
import com.im.tcp.handler.HeartBeatHandler;
import com.im.tcp.handler.NettyServerHandler;
import com.im.tcp.publish.MqMessageProducer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * LimServer 类，用于启动Netty服务端
 */
@Slf4j
@Component
public class LimServer {

    @Autowired
    private TcpConfig nettyConfig; // Tcp配置对象
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private FeignMessageService feignMessageService;
    @Autowired
    private MqMessageProducer mqMessageProducer;

    private EventLoopGroup mainGroup; // 主EventLoopGroup
    private EventLoopGroup subGroup; // 子EventLoopGroup
    private ServerBootstrap server; // Netty服务端启动器

    /**
     * 构造函数，传入Tcp配置对象
     */
    @PostConstruct
    public void start() {
        // 创建主和子EventLoopGroup，用于处理客户端连接和I/O事件
        mainGroup = new NioEventLoopGroup(nettyConfig.getBossThreadSize());
        subGroup = new NioEventLoopGroup(nettyConfig.getWorkThreadSize());
        // 创建Netty服务端启动器
        server = new ServerBootstrap();
        // 配置启动器参数
        server.group(mainGroup, subGroup) // 设置主和子EventLoopGroup
                .channel(NioServerSocketChannel.class) // 指定使用NIO模式
                .option(ChannelOption.SO_BACKLOG, 10240) // 设置tcp的SO_BACKLOG参数，指定等待连接的最大队列长度
                .option(ChannelOption.SO_REUSEADDR, true) // 设置SO_REUSEADDR参数，表示允许重复使用本地地址和端口
                .option(ChannelOption.TCP_NODELAY, true) // 设置TCP_NODELAY参数，表示立即发送数据
                .option(ChannelOption.SO_KEEPALIVE, true) // 设置SO_KEEPALIVE参数，表示开启TCP心跳保活机制
                // 添加ChannelInitializer，用于初始化SocketChannel的ChannelPipeline
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 添加ChannelPipeline的处理器
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new MessageDecoder()); // 解码器，用于解码收到的消息
                        pipeline.addLast(new MessageEncoder()); // 编码器，用于编码发送的消息
                        pipeline.addLast(new IdleStateHandler(0, 0, 10)); // 用于触发空闲事件的Handler，参数分别为读空闲时间、写空闲时间、读写空闲时间
                        pipeline.addLast(new HeartBeatHandler(nettyConfig.getHeartBeatTime())); // 心跳处理器，用于处理客户端发来的心跳消息
                        pipeline.addLast(new NettyServerHandler(redissonClient, feignMessageService, nettyConfig, mqMessageProducer)); // 业务逻辑处理器


                    }
                });
        // 绑定端口并启动服务端
        server.bind(nettyConfig.getTcpPort());
        log.info("Tcp服务启动成功");
    }

}
